Návod k editaci JSON šablony — Dokument (faktura, dodací list)

Tento návod je určen pro úpravu JSON šablon obchodních dokumentů (faktury, dodací listy, objednávky, nabídky) ve VS Code s live preview.

Obsah:


Jak to funguje

┌───────────────────────────────────────────────────────────┐
│  XML data         +    JSON šablona    →    HTML / PDF    │
│  (z aplikace)          (vaše úpravy)        (výstup)      │
└───────────────────────────────────────────────────────────┘

XML data — připraví aplikace. Obsahují data dokumentu: dodavatel, odběratel, položky, ceny.

JSON šablona — tu upravujete vy. Říká rendereru, jak má dokument vypadat: jaké bloky, v jakém pořadí, s jakými daty.

Výstup — HTML (náhled), PDF (tisk/email).


Editace ve VS Code

Editaci spustíte z aplikace. Otevře se VS Code s JSON souborem a v prohlížeči se zobrazí HTML náhled.

Základní workflow

  1. Otevřete editaci z aplikace (tlačítko "Upravit šablonu")
  2. VS Code se otevře se JSON souborem, v prohlížeči se zobrazí náhled
  3. Upravte JSON šablonu ve VS Code
  4. Uložte (Ctrl+S) — náhled v prohlížeči se automaticky obnoví za ~2 sekundy
  5. Zkontrolujte výsledek v prohlížeči
  6. Opakujte kroky 3–5

VS Code nápověda

Pozor: JSON soubor musí být validní. Nejčastější chyba: čárka za poslední položkou v {} nebo []. VS Code chybu červeně podtrhne.


Princip: Dokument = posloupnost bloků

Na rozdíl od tabulkové sestavy (kde je jedna velká tabulka), dokument se skládá z bloků, které se řadí shora dolů. Každý blok má svůj typ a vlastnosti.

{
  "renderer":   "document",  ← typ šablony (volitelné, pro jednoznačnou identifikaci)
  "aliases":    { ... },     ← zkratky pro dlouhé XML cesty (volitelné)
  "document":   { ... },     ← nastavení dokumentu
  "pageHeader": { ... },     ← záhlaví stránky (opakuje se)
  "pageFooter": { ... },     ← zápatí stránky (opakuje se)
  "blocks": [                ← pole bloků — v tomto pořadí se vykreslí
    { "type": "header-two-column", ... },
    { "type": "info-grid", ... },
    { "type": "table", ... },
    { "type": "total-amount", ... },
    { "type": "signature", ... }
  ]
}

1. Nastavení dokumentu (document)

{
  "document": {
    "title": "FAKTURA – daňový doklad",
    "culture": "cs-CZ",
    "orientation": "portrait",
    "pageSize": "A4",
    "pageMarginMm": 8,
    "overflow": "auto"
  }
}
Vlastnost Co dělá Příklad
renderer Typ šablony (volitelné — bez něj se typ pozná z obsahu JSON) "document"
title Název dokumentu (podporuje {element.field} placeholdery) "FAKTURA – daňový doklad", "Inventura účtu {ucty.ucet}"
culture Formát čísel/datumů "cs-CZ"
orientation Orientace "portrait" (výška), "landscape" (šířka)
pageSize Velikost papíru "A4", "A3", "Letter"
pageMarginMm Okraje stránky v mm 8
overflow Jak řešit dlouhý dokument viz níže
fontSizePt Základní velikost písma v pt (vše se škáluje) 9 (výchozí), 8, 10
fontFamily Název písma dokumentu "Segoe UI" (výchozí), "Arial", "Calibri"
attachmentTitle Titulek přílohy (attachment mode). "" = potlačit "PŘÍLOHA k faktuře {header.faktura}"
attachmentRef Text „viz příloha" na straně 1. "" = potlačit "Rozpis položek viz příloha"
repeatElement Opakování dokumentu pro kolekci (viz sekce 19) "upominky"
pageBreakBetween Page-break mezi opakovanými dokumenty true (výchozí)
resetPageNumbers Resetovat číslování stránek pro každý opakovaný dokument false (výchozí)

Režimy stránkování (overflow)

Režim Kdy použít
"flow" Vše na jedné stránce (krátký dokument)
"auto" Doporučeno — automaticky rozhodne: krátký → flow, dlouhý → attachment
"continue" Stránkování s opakujícím se záhlavím/zápatím
"attachment" Strana 1 = hlavička + "viz příloha", strany 2+ = tabulka položek
"paged" Plnohodnotné stránkování řádek po řádku — pro výkazy jako rozvaha, kde tabulky přesahují stránku

Tip: Pro faktury použijte "auto" — krátké faktury se vejdou na 1 stránku, dlouhé se automaticky roztáhnou do přílohy.

Rozvaha a podobné výkazy: Použijte "paged" — každá tabulka se automaticky stránkuje řádek po řádku, záhlaví tabulky se opakuje na každé stránce.

Příklad: Rozvaha se dvěma tabulkami (aktiva/pasiva) v paged mode

{
  "renderer": "document",
  "document": {
    "title": "{header.title}",
    "culture": "cs-CZ",
    "pageMarginMm": 8,
    "overflow": "paged",
    "fontSizePt": 8
  },
  "pageHeader": {
    "left": "{header.title}",
    "right": "Strana {page}",
    "heightMm": 8,
    "fromPage": 2
  },
  "blocks": [
    {
      "type": "table",
      "element": "data",
      "where": "lk1=A",
      "headerRows": [
        [
          { "text": "Označ.", "rowspan": 2, "align": "center" },
          { "text": "A K T I V A", "rowspan": 2 },
          { "text": "Číslo\nřádku", "rowspan": 2, "align": "center" },
          { "text": "Běžné účetní období", "colspan": 3, "align": "center" },
          { "text": "Minulé úč.\nobdobí", "rowspan": 2, "align": "center" }
        ],
        [
          { "text": "Brutto", "align": "center" },
          { "text": "Korekce", "align": "center" },
          { "text": "Netto", "align": "center" }
        ]
      ],
      "columns": {
        "klic_tisk": { "label": "k", "width": "13mm" },
        "nazev":     { "label": "Název", "width": "60mm", "maxWidth": "60mm" },
        "radek":     { "label": "ř.", "align": "center", "format": "N0", "suppressRepeat": true, "width": "10mm" },
        "brutto":    { "label": "Brutto", "align": "right", "format": "{prnobj.format}", "hideZero": true, "width": "25mm" },
        "korekce":   { "label": "Korekce", "align": "right", "format": "{prnobj.format}", "hideZero": true, "width": "25mm" },
        "netto":     { "label": "Netto", "align": "right", "format": "{prnobj.format}", "hideZero": true, "width": "25mm" },
        "loni":      { "label": "Loni", "align": "right", "format": "{prnobj.format}", "hideZero": true, "width": "25mm" }
      }
    },
    {
      "type": "table",
      "element": "data",
      "where": "lk1=P",
      "pageBreakBefore": true,
      "columns": {
        "klic_tisk": { "label": "k", "width": "13mm" },
        "nazev": { "label": "Název", "width": "80mm", "maxWidth": "100mm" },
        "radek": { "label": "ř.", "align": "center", "suppressRepeat": true, "width": "10mm" },
        "netto": { "label": "Netto", "align": "right", "format": "{prnobj.format}", "hideZero": true, "width": "35mm" },
        "loni":  { "label": "Loni", "align": "right", "format": "{prnobj.format}", "hideZero": true, "width": "35mm" }
      }
    }
  ]
}

Klíčové prvky rozvahy:


Opakuje se na každé stránce (v režimech continue, auto/attachment):

{
  "pageHeader": {
    "left": "EFES spol. s r.o.",
    "center": "",
    "right": "Strana {page} z {pages}",
    "fromPage": 2
  },
  "pageFooter": {
    "center": "Vytištěno: {date}"
  }
}
Placeholder Co zobrazí
{page} Číslo stránky
{pages} Celkový počet stránek
{title} Název dokumentu
{date} Aktuální datum (dd.MM.yyyy)
{datetime} Aktuální datum a čas (dd.MM.yyyy HH:mm:ss)

fromPage: 2 — záhlaví se zobrazí až od 2. stránky (1. stránka má vlastní hlavičku).


Přehled typů bloků (13)

Typ K čemu slouží Typické použití
header-two-column Dvě adresy vedle sebe Dodavatel + odběratel
info-grid Tabulka klíč-hodnota Číslo FV, VS, datumy
table Datová tabulka s řádky Položky faktury
form-table Formulářová tabulka s pevnými řádky Daňová přiznání (DPH)
total-amount Celková částka "Celkem k úhradě: 75 020 Kč"
text-block Volný text Poznámky, zápis v OR
signature Podpisy Vystavil / Převzal
separator Vodorovná čára Oddělení sekcí
spacer Prázdný prostor Vertikální mezera
image Obrázek Logo, fotografie
qr-code QR kód QR platba
barcode Čárový kód EAN produktu
columns Bloky vedle sebe QR kód vedle tabulky

3. Blok header-two-column — dodavatel a odběratel

{
  "type": "header-two-column",
  "ratio": "50:50",
  "left": {
    "title": "DODAVATEL",
    "element": "dodavatel",
    "logo": { "file": "logo.jpg", "maxWidthMm": 30, "position": "left" },
    "fields": [
      { "field": "nazev", "style": "title" },
      { "field": "ulice" },
      { "template": "{psc}  {mesto}" },
      { "separator": true },
      { "label": "IČO", "field": "ico" },
      { "label": "DIČ", "field": "dic" }
    ]
  },
  "right": {
    "title": "ODBĚRATEL",
    "element": "odberatel",
    "bordered": true,
    "fields": [
      { "field": "nazev", "style": "title" },
      { "field": "ulice" },
      { "template": "{psc}  {mesto}" },
      { "separator": true },
      { "label": "IČO", "field": "ico" },
      { "label": "DIČ", "field": "dic", "visibleWhen": "odberatel.dic" }
    ]
  }
}

Vizuální schéma

┌─────────────────────────┬───────────────────────────┐
│ DODAVATEL               │ ┌─ODBĚRATEL─────────────┐ │
│ [logo] EFES spol. s r.o.│ │ BAKPA INVEST s.r.o.   │ │
│        Neklanova 18     │ │ Komoranská 2428/17    │ │
│        128 00 Praha 2   │ │ 143 00 Praha 4        │ │
│ ──────────────────────  │ │ ────────────────────  │ │
│ IČO: 13150529           │ │ IČO: 07240244         │ │
│ DIČ: CZ6209260915       │ │                       │ │
│                         │ └───────────────────────┘ │
└─────────────────────────┴───────────────────────────┘

Vlastnosti sloupce (left/right)

Vlastnost Co dělá Příklad
title Nadpis nad adresou "DODAVATEL"
element XML element s daty (podporuje tečkovou notaci: "faktura.dodavatel") "dodavatel"
bordered Rámeček kolem true
logo Logo v hlavičce viz níže
fields Pole s údaji viz níže

Pole (fields) — typy řádků

{ "field": "nazev", "style": "title" }     ← hodnota z XML, tučně
{ "field": "ulice" }                        ← hodnota z XML
{ "label": "IČO", "field": "ico" }         ← popisek + hodnota
{ "template": "{psc}  {mesto}" }            ← šablona z více polí
{ "separator": true }                       ← oddělovací čára
{ "type": "spacer", "heightMm": 5 }        ← prázdný prostor

Tip: Pokud je XML hodnota prázdná, řádek se automaticky skryje (včetně popisku). Pokud chcete zobrazit i prázdný řádek, použijte template místo field.

Vlastnost Co dělá
field Název XML atributu
label Popisek před hodnotou
template Šablona: "{psc} {mesto}"
style "title", "bold", "italic", "bold-italic", "small" + suffix -right/-center pro zarovnání (např. "title-right", "bold-center")
format Formát: "dd.MM.yyyy", "N2"
separator Oddělovací čára (alternativně { "type": "separator" })
type "spacer" = prázdný prostor, "separator" = oddělovací čára
heightMm Výška spaceru v mm (výchozí 5)
visibleWhen Podmíněná viditelnost
{
  "logo": {
    "file": "C:\\data\\logo.jpg",
    "maxWidthMm": 30,
    "position": "left"
  }
}
Vlastnost Co dělá
file Cesta k souboru
maxWidthMm Max. šířka v mm
maxHeightMm Max. výška v mm
position "top" (logo nad textem), "left" (logo vedle textu)

4. Blok info-grid — mřížka klíč-hodnota

{
  "type": "info-grid",
  "element": "doklad",
  "columns": 2,
  "labelWidth": "40%",
  "borderless": true,
  "items": [
    { "label": "Číslo faktury",     "field": "cislo",     "style": "title" },
    { "label": "Variabilní symbol", "field": "vs" },
    { "separator": true },
    { "label": "Způsob úhrady",     "template": "Příkazem k úhradě" },
    { "label": "Den splatnosti",    "field": "splatnost", "format": "dd.MM.yyyy", "style": "bold" },
    { "label": "Den vystavení",     "field": "vystaveni", "format": "dd.MM.yyyy" }
  ]
}

Vizuální schéma

┌──────────────────────────────────────────────────────────┐
│ Číslo faktury:  FV2600244     Variabilní symbol: 2600244 │
│ ──────────────────────────────────────────────────────── │
│ Způsob úhrady: Příkazem      Den splatnosti: 16.02.2026 │
│                               Den vystavení:  02.02.2026 │
└──────────────────────────────────────────────────────────┘
Vlastnost Co dělá Příklad
element XML element s daty "doklad"
columns Počet sloupců (1–3) 2
labelWidth Šířka popisku "40%"
borderless Bez horní/dolní čáry true

Položka info-grid

Vlastnost Co dělá
label Popisek
field XML atribut
template Statický text nebo {field} šablona (vždy viditelný)
format Formát: "dd.MM.yyyy", "N2"
style "title", "bold", "italic", "bold-italic", "small", "muted" + suffix -right/-center (např. "title-right")
separator Oddělovací čára
visibleWhen Podmíněná viditelnost
heightMm Minimální výška value boxu v mm (pro form styl)

Info-grid v praxi (XML → JSON → výstup)

XML data:

<doklad cislo="FV2600244" vs="2600244" splatnost="2026-02-16" />

JSON definice:

{
  "type": "info-grid", "element": "doklad", "columns": 2,
  "items": [
    { "label": "Číslo faktury", "field": "cislo", "style": "title" },
    { "label": "VS", "field": "vs" },
    { "label": "Splatnost", "field": "splatnost", "format": "dd.MM.yyyy", "style": "bold" }
  ]
}

Výstup:

Číslo faktury: FV2600244 VS: 2600244
Splatnost: 16.02.2026

Formulářový styl (fieldStyle: "form")

Pro úřední formuláře (daňová přiznání apod.) kde potřebujete popisek nahoře a orámovaný textbox pod ním:

{
  "type": "info-grid",
  "element": "hlavicka",
  "columns": 2,
  "fieldStyle": "form",
  "items": [
    { "label": "Finančnímu úřadu pro", "field": "nazev_fu" },
    { "label": "DIČ", "field": "dic", "style": "bold" }
  ]
}
Finančnímu úřadu pro        DIČ
┌──────────────────┐        ┌──────────────────┐
│ hlavní město     │        │ CZ41189710       │
└──────────────────┘        └──────────────────┘

Klíčové vlastnosti:

Styl form-inline — popisek vlevo, textbox vpravo

{
  "type": "info-grid",
  "element": "hlavicka",
  "fieldStyle": "form-inline",
  "columns": 3,
  "items": [
    { "label": "řádné", "field": "cb_radne", "style": "bold", "width": "10mm" },
    { "label": "dodatečné", "field": "cb_dodatecne", "width": "10mm" },
    { "label": "opravné", "field": "cb_opravne", "width": "10mm" }
  ]
}
řádné ┌──┐   dodatečné ┌──┐   opravné ┌──┐
      │ X│             │  │           │  │
      └──┘             └──┘           └──┘

Na rozdíl od "form" (label nahoře, box dole), "form-inline" umístí popisek vlevo a orámovaný textbox vpravo na jednom řádku. Typické pro formuláře typu DPH přiznání.

Vlastnost Co dělá Příklad
width na položce Fixní šířka textboxu "10mm", "22mm"
align: "right" na položce Textbox zarovnaný k pravému okraji (label vlevo, box úplně vpravo)

Kompaktní řádkování (compact)

{
  "type": "info-grid",
  "element": "hlavicka",
  "compact": true,
  "items": [ ... ]
}

Vlastnost compact: true zmenší padding a řádkování v info-gridu. Užitečné pro formuláře s mnoha řádky.


5. Blok table — tabulka s položkami

{
  "type": "table",
  "element": "polozky",
  "primary": true,
  "showRowNumbers": true,
  "columns": {
    "nazev":  { "label": "Název",     "align": "left" },
    "pocet":  { "label": "Množství",  "align": "right", "format": "N2", "width": "60px" },
    "mj":     { "label": "MJ",        "align": "center", "width": "30px" },
    "jc":     { "label": "Cena/ks",   "align": "right", "format": "N2", "width": "80px" },
    "cena":   { "label": "Celkem",    "align": "right", "format": "N2", "width": "90px" }
  },
  "sumExpressions": [
    { "field": "cena", "expr": "SUM(cena)", "format": "N2" }
  ],
  "sumLabel": "Celkem"
}

Vizuální schéma

┌────┬──────────────────────┬──────────┬─────┬──────────┬───────────┐
│ #  │ Název                │ Množství │ MJ  │ Cena/ks  │ Celkem    │
├────┼──────────────────────┼──────────┼─────┼──────────┼───────────┤
│ 1  │ Služby VT            │    40,00 │ h   │ 1 815,00 │ 72 600,00 │
│ 2  │ Správa serveru       │     1,00 │ ks  │ 2 420,00 │  2 420,00 │
├────┼──────────────────────┼──────────┼─────┼──────────┼───────────┤
│    │ Celkem               │          │     │          │ 75 020,00 │
└────┴──────────────────────┴──────────┴─────┴──────────┴───────────┘
Vlastnost Co dělá Příklad
element XML element s <row> potomky "polozky"
where Filtr řádků ze sdíleného elementu: "lk1=A", "stav!=Z", "pole" (neprázdné) "lk1=A"
primary Primární tabulka (pro attachment mode) true
showRowNumbers Sloupec s číslem řádku (#) true
compact Menší písmo a padding true
hideZero Skrýt nulové hodnoty true
columns Definice sloupců viz níže
sumExpressions Součty viz tabulkový návod
sumLabel Popisek součtu "Celkem"
filterBy Filtrování řádků podle repeat prvku (viz sekce 19) ["organizace"]
headerRows Víceřádkové záhlaví tabulky s colspan/rowspan. Nahradí automatické záhlaví z columns.label. viz níže
detailBorders Styl čar mezi datovými řádky: "all", "h-dashed", "none", "vertical", ... (viz sekce 23) "h-dashed"
groups Skupiny v tabulce — záhlaví skupiny, sum řádky skupiny, grand total (viz sekce 23) viz níže

headerRows — víceřádkové záhlaví tabulky

Pokud tabulka potřebuje složitější záhlaví (např. rozvaha se sloučenými buňkami), použijte headerRows. Každý prvek pole = jeden řádek záhlaví, každý řádek = pole buněk.

{
  "type": "table",
  "element": "aktiva",
  "headerRows": [
    [
      { "text": "Označ.", "rowspan": 2 },
      { "text": "A K T I V A", "rowspan": 2 },
      { "text": "Číslo\nřádku", "rowspan": 2 },
      { "text": "Běžné účetní období", "colspan": 3, "align": "center" },
      { "text": "Minulé úč.\nobdobí", "rowspan": 2, "align": "center" }
    ],
    [
      { "text": "Brutto\n1", "align": "center" },
      { "text": "Korekce\n2", "align": "center" },
      { "text": "Netto\n3", "align": "center" }
    ]
  ],
  "columns": { ... }
}

Vlastnosti buňky záhlaví:

Vlastnost Výchozí Popis
text "" Text buňky (\n pro nový řádek)
colspan 1 Sloučení sloupců doprava
rowspan 1 Sloučení řádků dolů
align z columns Zarovnání: "left", "center", "right"
style "bold" Styl: "bold", "normal"
background výchozí CSS barva pozadí

Tip: Pokud headerRows chybí, záhlaví se generuje automaticky z columns[].label (jednořádkové) — zpětná kompatibilita.

Sloupce tabulky — stejné jako v tabulkové sestavě

Sloupce dokumentové tabulky mají stejné vlastnosti jako v tabulkové sestavě: label, align, format, width, maxWidth, hide, hideZero, suppressRepeat, expr, round, running, template, visibleWhen.

Vlastnost Popis
suppressRepeat Potlačit opakované hodnoty — zobrazí se jen při změně (jako FoxPro suppressRepeat). Typicky na sloupci číslo řádku.
maxWidth Max šířka s word-wrapem (např. "60mm"). Text se zalomí na více řádků.
format Může být dynamický: "{prnobj.format}" — hodnota se vezme z XML atributu před renderováním.

Tabulka v praxi (XML → JSON → výstup)

XML data:

<polozky>
  <row nazev="Služby VT" pocet="40" mj="h" jc="1815" cena="72600" />
  <row nazev="Správa serveru" pocet="1" mj="ks" jc="2420" cena="2420" />
</polozky>

JSON definice:

"columns": {
  "nazev": { "label": "Název" },
  "pocet": { "label": "Mn.", "align": "right", "format": "N2" },
  "jc":    { "label": "Cena/ks", "align": "right", "format": "N2" },
  "cena":  { "label": "Celkem", "align": "right", "format": "N2" }
}

Výstup:

Název Mn. Cena/ks Celkem
Služby VT 40,00 1 815,00 72 600,00
Správa serveru 1,00 2 420,00 2 420,00

SubFields — doplňkový řádek pod položkou

{
  "subFields": [
    { "field": "ean",      "label": "EAN" },
    { "field": "sarze",    "label": "Šarže" },
    { "field": "poznamka" }
  ]
}
│ 1  │ Služby VT                    │  40,00 │ h  │ 72 600,00 │
│    │ EAN: 8594001234567 | Šarže: L2026-01                    │

SubFields se zobrazí na druhém řádku pod hlavním. Pokud jsou všechny prázdné, řádek se nevykreslí.

Vlastnost Co dělá
field XML atribut
label Popisek (volitelný)
format Formát hodnoty
visibleWhen Podmíněná viditelnost

SubFields podporují Markdown s prefixem ^ (viz blok text-block).

Cross-element přístup (tečková notace) v tabulce

Sloupec tabulky může přistupovat k hodnotám z jiného XML elementu:

{
  "columns": {
    "cizi":    { "label": "Cena {header.mena}", "format": "N2" },
    "prepocet": { "label": "Cena Kč", "expr": "cizi * header.kurz", "format": "N2" },
    "s_menou": { "label": "Celkem",  "template": "{cena:N2} {header.mena}" }
  }
}

Tečková notace funguje i v dalších blocích — viz sekci 17.


6. Blok form-table — formulářová tabulka

Blok form-table slouží pro tisk formulářů s pevně danými řádky — typicky daňová přiznání (DPH, silniční daň apod.). Na rozdíl od bloku table, kde řádky pocházejí z XML dat, zde jsou řádky definované přímo v JSON a data se doplňují z XML přes klíč (keyField).

Vizuální schéma

┌────────────────────────────────────────────────────────────────┐
│ I. Zdanitelná plnění                                           │
├──────────────────────────────────────┬────┬──────────┬─────────┤
│ Dodání zboží (§13, §14)    základní │  1 │ 1 752 218│  367 966│
│                             snížená │  2 │72 591 721│8 711 007│
│ Pořízení z JČS (§16)       základní │  3 │         0│        0│
│                             snížená │  4 │49 637 566│5 956 508│
└──────────────────────────────────────┴────┴──────────┴─────────┘

Základní struktura

{
  "type": "form-table",
  "element": "dph",
  "keyField": "r1",
  "sections": [
    {
      "title": "I. Zdanitelná plnění",
      "columns": {
        "popis": { "width": "53%" },
        "sazba": { "width": "8%", "fontSize": 7, "align": "center" },
        "radek": { "label": "ř.", "width": "4%", "align": "center" },
        "s2":    { "label": "Základ daně", "width": "17%", "align": "right", "format": "N0" },
        "s3":    { "label": "Daň na výstupu", "width": "18%", "align": "right", "format": "N0" }
      },
      "rows": [
        {
          "popis": { "value": "Dodání zboží (§13, §14)", "rowspan": 2 },
          "sazba": "základní", "radek": "1", "_key": "001"
        },
        { "sazba": "snížená", "radek": "2", "_key": "002" }
      ]
    }
  ]
}

Klíčové vlastnosti bloku

Vlastnost Co dělá Příklad
element XML element s daty "dph"
keyField Atribut v XML pro párování řádků "r1"
sections Pole sekcí tabulky viz níže
fontSize Velikost písma celé tabulky (pt) 8

Sekce

Každá sekce má vlastní nadpis, sloupce a řádky:

Vlastnost Co dělá Příklad
title Nadpis sekce (šedé pozadí) "I. Zdanitelná plnění"
columns Definice sloupců sekce viz níže
rows Pole řádků s daty viz níže
showHeader Zobrazit záhlaví sloupců (true/false) false — skryje záhlaví

Sloupce

Sloupce se definují jako objekt — klíč = název, hodnota = vlastnosti:

Vlastnost Co dělá Příklad
label Záhlaví sloupce "Základ daně"
width Šířka (% nebo px) "17%"
align Zarovnání (left/center/right) "right"
format Formát čísla "N0" = celá čísla, "N2" = 2 des. místa
fontSize Velikost písma sloupce (pt) 7

Řádky

Každý řádek je objekt. Klíče odpovídají sloupcům. Speciální klíče začínají _:

Vlastnost Co dělá Příklad
_key Klíč pro párování s XML "001" → hledá <row r1="001" .../>
_bold Tučný řádek true
_fontSize Velikost písma řádku (pt) 9
_noBorder Bez dolního okraje true

Hodnoty buněk

Hodnota buňky může být:

Prostý text/číslo — hodnota z JSON nebo doplněná z XML:

{ "sazba": "základní", "radek": "1", "_key": "001" }

Objekt s vlastnostmi — pro rowspan, colspan, formát, zarovnání:

{
  "popis": { "value": "Dodání zboží (§13, §14)", "rowspan": 2 },
  "sazba": "základní"
}
Vlastnost buňky Co dělá Příklad
value Text buňky "Dodání zboží"
rowspan Sloučení řádků dolů 2
colspan Sloučení sloupců doprava 3
format Přepíše formát sloupce "N2" (koeficient v jinak N0 sloupci)
align Přepíše zarovnání sloupce "center"
template Šablona s {field} placeholdery "{s2:N2} %"

Jak funguje párování s XML

  1. V JSON definujete řádek s "_key": "001"
  2. Renderer hledá v XML element s keyField hodnotou "001":
    <dph>
      <row r1="001" s2="1752218" s3="367966"/>
    </dph>
    
  3. Datové sloupce (s2, s3) se doplní z nalezeného XML řádku
  4. Textové sloupce (popis, sazba, radek) zůstanou z JSON
  5. Pokud XML řádek neexistuje, datové buňky zůstanou prázdné

Pozor: Hodnoty _key v JSON musí přesně odpovídat hodnotám keyField v XML. Pokud se data nezobrazují, zkontrolujte, že se klíče shodují (včetně mezer a formátu čísla).

Příklad: Sekce s různými sloupci

Různé sekce mohou mít různé sloupce (např. sekce I má 5 sloupců, sekce II jen 3):

{
  "title": "II. Ostatní plnění",
  "columns": {
    "popis": { "width": "74%" },
    "radek": { "label": "ř.", "width": "4%", "align": "center" },
    "s3":    { "label": "Hodnota", "width": "22%", "align": "right", "format": "N0" }
  },
  "rows": [
    { "popis": "Dodání zboží do JČS (§64)", "radek": "20", "_key": "020" },
    { "popis": "Vývoz zboží (§66)", "radek": "22", "_key": "022" }
  ]
}

Sekce bez záhlaví

Některé sekce nepotřebují opakovat záhlaví sloupců — použijte "showHeader": false:

{
  "title": "V. Krácení nároku na odpočet daně",
  "showHeader": false,
  "columns": { ... },
  "rows": [ ... ]
}

7. Blok total-amount — celková částka

{
  "type": "total-amount",
  "element": "doklad",
  "field": "celkem_s_dph",
  "label": "Celkem k úhradě",
  "format": "N2",
  "suffix": "Kč"
}

Vizuální schéma

Celkem k úhradě .............. 75 020,00 Kč
Vlastnost Co dělá Příklad
element XML element "doklad"
field Pole s částkou "celkem_s_dph"
label Popisek vlevo, podporuje {element.field} a {date} "Celkem k {doklad.ke_dni}:"
format Formát čísla "N2"
suffix Text za částkou, podporuje {field} a {element.field} "Kč" nebo "{mena}"
style "large" pro větší písmo

8. Blok text-block — volný text

Statický text

{
  "type": "text-block",
  "lines": [
    "Fakturujeme Vám za dodané služby.",
    "Ceny jsou zaokrouhleny na celé Kč."
  ]
}

Dynamický text z XML

{
  "type": "text-block",
  "element": "header",
  "field": "text_pod_r"
}

Dynamický text s labelem

Label se překládá přes dictionary a zobrazí se jen pokud je pole neprázdné:

{
  "type": "text-block",
  "element": "header",
  "field": "zpracoval",
  "label": "Vyřizuje"
}

Výstup: „Vyřizuje: Marianna Dávidházy"

Šablona s placeholdery

{
  "type": "text-block",
  "element": "doklad",
  "template": "Objednávka č. {objednavka} ze dne {datum_obj:dd.MM.yyyy}"
}

Dynamické řádky

{
  "type": "text-block",
  "element": "dodavatel",
  "lines": ["{rejstrik}"],
  "style": "small"
}
Vlastnost Co dělá
lines Řádky textu
element XML element pro placeholdery
field Pole s textem (auto-hide když prázdné)
label Popisek před hodnotou — „Label: hodnota" (překládá se přes dictionary)
template Šablona s {pole} placeholdery
style "title", "bold", "italic", "bold-italic", "small" (malé šedě) + suffix -right/-center (např. "bold-right")
align Zarovnání textu: "left", "center", "right" (přepíše výchozí ze style)
fontSize Velikost písma v pt (přepíše výchozí)

Příklad — text s vlastním zarovnáním a velikostí:

{
  "type": "text-block",
  "lines": ["Strana 1"],
  "align": "center",
  "fontSize": 12
}

Markdown (prefix ^)

Textové hodnoty začínající ^ se zpracují jako Markdown:

XML:  text_pod_r="^**Důležité:** zboží je ==nereklamovatelné=="
Markdown Výsledek
**tučné** tučné
*kurzíva* kurzíva
==zvýrazněné== zvýrazněné (žlutě)
* odrážka odrážkový seznam
1. číslovaný číslovaný seznam

Markdown funguje v: text-block (field, lines), subFields tabulky.


9. Blok signature — podpisy

{
  "type": "signature",
  "left": "Vystavil: {doklad.vystavil}",
  "right": "Razítko a podpis dodavatele:\nPřevzal: _______________"
}

Vizuální schéma

Vystavil: Novák Jan                    Razítko a podpis dodavatele:
                                       Převzal: _______________
Vlastnost Co dělá
left Levý podpis. Podporuje {field}, {element.field}, {date}, \n = nový řádek
right Pravý podpis. Stejné placeholdery jako left
leftImage Obrázek razítka/podpisu vlevo
rightImage Obrázek razítka/podpisu vpravo

10. Blok separator — čára

{ "type": "separator" }
{ "type": "separator", "style": "thick" }
{ "type": "separator", "style": "double" }
Styl Jak vypadá
(žádný) Tenká šedá čára
"thick" Tlustá čára
"double" Dvojitá čára

11. Blok spacer — mezera

{ "type": "spacer", "heightMm": 15 }

Vloží prázdné místo zadané výšky.


12. Blok image — obrázek

{
  "type": "image",
  "file": "logo.png",
  "maxWidthMm": 40,
  "align": "center"
}
Vlastnost Co dělá
file Cesta k souboru
src Přímé base64 data
element + field Dynamicky z XML
maxWidthMm Max. šířka v mm
maxHeightMm Max. výška v mm
align "left", "center", "right"

13. Blok qr-code — QR kód

{
  "type": "qr-code",
  "template": "SPD*1.0*ACC:{ucet.iban}*AM:{doklad.celkem}*CC:CZK*MSG:Faktura {doklad.cislo}",
  "sizeMm": 30,
  "label": "QR platba"
}
Vlastnost Co dělá
content Statický text QR kódu
template Šablona s {element.field} placeholdery
element + field Hodnota z XML
sizeMm Velikost v mm (výchozí 35)
label Popisek
labelPosition "above" nebo "below"

14. Blok barcode — čárový kód

{
  "type": "barcode",
  "content": "8594001234567",
  "format": "EAN-13",
  "widthMm": 50,
  "heightMm": 15,
  "showText": true
}
Vlastnost Co dělá
content Obsah kódu
format "EAN-13", "EAN-8", "Code128", "Code39", "UPC-A"
widthMm Šířka v mm
heightMm Výška v mm
showText Zobrazit text pod kódem

15. Blok columns — bloky vedle sebe

Umístí libovolné bloky do sloupců vedle sebe:

{
  "type": "columns",
  "ratio": "70:30",
  "verticalAlign": "center",
  "columns": [
    {
      "blocks": [
        { "type": "table", ... }
      ]
    },
    {
      "blocks": [
        { "type": "qr-code", ... }
      ]
    }
  ]
}

Vizuální schéma

┌──────────────────────────────────┬──────────────┐
│                                  │              │
│  TABULKA POLOŽEK                 │   ┌──────┐   │
│  ┌────┬──────┬──────┐           │   │ QR   │   │
│  │ #  │ Naz. │ Cena │           │   │ kód  │   │
│  ├────┼──────┼──────┤           │   └──────┘   │
│  │ 1  │ ...  │ ...  │           │   QR platba  │
│  └────┴──────┴──────┘           │              │
│                                  │              │
└──────────────────────────────────┴──────────────┘
          70 %                          30 %
Vlastnost Co dělá Příklad
ratio Poměr šířek sloupců "50:50", "70:30", "25:50:25"
verticalAlign Svislé zarovnání "top", "center", "bottom"
gap Mezera mezi sloupci (px) 15

Uvnitř columns mohou být libovolné bloky, včetně dalších columns (vnořování).

Rámeček kolem sloupce (border)

{
  "type": "columns",
  "ratio": "50:50",
  "columns": [
    {
      "blocks": [ { "type": "info-grid", ... } ]
    },
    {
      "border": true,
      "blocks": [
        { "type": "spacer", "heightMm": 28 },
        { "type": "text-block", "style": "small", "lines": ["Otisk podacího razítka"] }
      ]
    }
  ]
}

Vlastnost border: true na sloupci přidá viditelný šedý rámeček (1px solid) s vnitřním paddingem. Typické pro formuláře — rámeček kolem prostoru pro razítko nebo podpis.


16. Podmíněná viditelnost (visibleWhen)

Kterýkoliv blok (nebo jeho část) můžete podmíněně skrýt/zobrazit:

{ "type": "info-grid", "visibleWhen": "header.je_cizi_mena", ... }
Podmínka Popis Příklad
"pole" Zobrazit pokud pole má hodnotu "header.je_platce"
"!pole" Zobrazit pokud pole je prázdné "!header.sleva"
"pole=hodnota" Zobrazit pokud pole = hodnota "header.mena=EUR"
"pole!=hodnota" Zobrazit pokud pole ≠ hodnota "header.mena!=CZK"
"pole>hodnota" Číslo větší než "header.kurz>1"
"pole>=hodnota" Číslo větší nebo rovno "header.sazba>=21"
"pole<hodnota" Číslo menší než "header.sleva<100"
"pole<=hodnota" Číslo menší nebo rovno "header.pocet<=0"

visibleWhen funguje na:


17. Tečková notace — cross-element přístup

Tečková notace {element.field} umožňuje v šablonách odkazovat na hodnoty z jiného XML elementu než toho, ke kterému blok patří. Např. info-grid patří elementu doklad, ale potřebujete zobrazit měnu z elementu header.

Formát

{element.pole}           → prostá hodnota
{element.pole:N2}        → formátovaná hodnota (číslo, datum)
{element.pole:40}        → ořízne na 40 znaků
{element.pole:40.}       → ořízne na 40 + trojtečka …
{element.pole:40w}       → ořízne na poslední celé slovo ≤ 40
{element.pole:40w.}      → celé slovo + trojtečka …

Kde funguje

Místo Příklad
info-grid template "template": "{header.mena} (kurz {header.kurz:N2})"
header-two-column template "template": "IČO: {ico} \| Měna: {header.mena}"
text-block lines "lines": ["Měna: {header.mena}, kurz: {header.kurz:N2}"]
text-block template "template": "Faktura {header.cislo} ze dne {header.datum:dd.MM.yyyy}"
tabulka label "label": "Cena {header.mena}"
tabulka expr "expr": "cizi * header.kurz"
tabulka template "template": "{cena:N2} {header.mena}"
total-amount suffix "suffix": "{header.mena}"
signature text "left": "Vystavil: {header.vystavil}"
visibleWhen "visibleWhen": "header.je_cizi_mena"

Příklady

Info-grid — měna a kurz z hlavičky:

{
  "type": "info-grid",
  "element": "doklad",
  "items": [
    { "label": "Variabilní symbol", "field": "vs" },
    { "label": "Měna", "template": "{header.mena} (kurz {header.kurz:N2})" }
  ]
}

Text-block — šablona bez vlastního elementu:

{
  "type": "text-block",
  "template": "Faktura {header.cislo} vystavena dne {header.datum:dd.MM.yyyy}"
}

Text-block — řádky s kombinací vlastního elementu a cross-element:

{
  "type": "text-block",
  "element": "dodavatel",
  "lines": [
    "Dodavatel: {nazev}",
    "Měna: {header.mena}, kurz: {header.kurz:N2}"
  ]
}

Zde {nazev} se resolvuje z elementu dodavatel, {header.mena} z elementu header.

Pravidla


18. Aliasy pro XML cesty (aliases)

Pokud v šabloně opakovaně používáte dlouhé tečkové cesty, můžete si definovat zkratky:

{
  "aliases": {
    "dod": "faktura.dodavatel",
    "odb": "faktura.odberatel"
  },
  "blocks": [
    {
      "type": "header-two-column",
      "left": { "element": "dod", "fields": [...] },
      "right": { "element": "odb", "fields": [...] }
    }
  ]
}

19. Opakování dokumentu (repeatElement + filterBy)

Pokud potřebujete z jedné šablony vygenerovat N dokumentů najednou (např. hromadné upomínky, dopisy zákazníkům, výzvy k úhradě), použijte repeatElement. Renderer vezme jeden XML kontejner a pro každý jeho child element vygeneruje kompletní dokument se všemi bloky.

Jak to funguje

XML data:
  <upominky>                          ← repeatElement kontejner
    <row organizace="1001" firma="Alfa" ... />   ← 1. iterace → dokument 1
    <row organizace="1002" firma="Beta" ... />    ← 2. iterace → dokument 2
  </upominky>
  <pohledavky>                        ← sdílená plochá tabulka
    <row organizace="1001" faktura="FV001" ... />
    <row organizace="1001" faktura="FV002" ... />
    <row organizace="1002" faktura="FV003" ... />
  </pohledavky>

JSON šablona:
  repeatElement: "upominky"           ← iteruj přes child elementy
  bloky: záhlaví, text, tabulka s filterBy, podpis

Výstup:
  Dokument 1 (Alfa): záhlaví Alfa + tabulka FV001, FV002 + podpis
  --- page break ---
  Dokument 2 (Beta): záhlaví Beta + tabulka FV003 + podpis

Nastavení v document

{
  "document": {
    "repeatElement": "upominky",
    "pageBreakBetween": true,
    "overflow": "flow"
  }
}
Vlastnost Typ Výchozí Popis
repeatElement string Název XML kontejneru. Renderer iteruje přes jeho child elementy
pageBreakBetween bool true Vložit page-break mezi dokumenty. Při false se dokumenty řadí za sebe
resetPageNumbers bool false Resetovat číslování stránek pro každý opakovaný dokument. {page} začíná od 1 a {pages} odpovídá počtu stránek daného dokumentu
title string Podporuje {element.field} placeholdery. Při repeatElement se resolvuje pro každý dokument — použije se v HTML <title> i PDF titulku

Přístup k datům aktuálního repeat prvku

V blocích můžete přistupovat k atributům aktuálního repeat prvku stejně jako k jakémukoli jinému XML elementu:

{
  "type": "header-two-column",
  "right": {
    "title": "ODBĚRATEL",
    "element": "upominky",
    "bordered": true,
    "fields": [
      { "field": "firma", "style": "title" },
      { "field": "ulice" },
      { "template": "{psc}  {mesto}" }
    ]
  }
}

filterBy — filtrování tabulky podle repeat prvku

Bez filterBy by tabulka zobrazila všechny řádky XML elementu. S filterBy zobrazí jen řádky odpovídající aktuálnímu záznamu:

{
  "type": "table",
  "element": "pohledavky",
  "filterBy": ["organizace"],
  "columns": {
    "faktura": { "label": "Faktura" },
    "castka": { "label": "Částka", "format": "N2", "align": "right" }
  },
  "sumExpressions": [
    { "field": "castka", "expr": "SUM(castka)", "format": "N2" }
  ]
}

filterBy: ["organizace"] znamená: zobraz jen řádky kde pohledavky.row.organizace == upominky.row.organizace.

Tři varianty zápisu filterBy

1. String — stejný název pole v obou tabulkách (nejčastější):

"filterBy": ["organizace", "mena"]

2. Objekt — různé názvy polí v tabulce a v repeat prvku:

"filterBy": [
  { "field": "org_id", "sourceField": "organizace" }
]

3. Objekt se sourceElement — zdrojová hodnota z jiného XML elementu:

"filterBy": [
  { "field": "stredisko", "sourceField": "stredisko", "sourceElement": "parametr" }
]

Vlastnosti filterBy položky

Vlastnost Typ Povinný Popis
(string) string Zkrácený zápis: název pole stejný v tabulce i v repeat prvku
field string ano Název pole v datové tabulce
sourceField string ne Název pole v repeat prvku. Pokud neuvedeno, použije se field
sourceElement string ne XML element pro zdrojovou hodnotu (místo repeat prvku)

Důležité:

Přístup k prvnímu řádku filtrovaných tabulek z ostatních bloků

V kontextu repeatElement jsou pole z první filtrované věty každé tabulky dostupná v ostatních blocích (text-block, info-grid, total-amount, signature atd.) přes tečkovou notaci {element.field}:

{
  "document": { "repeatElement": "upominky" },
  "blocks": [
    {
      "type": "table",
      "element": "pohledavky",
      "filterBy": ["organizace"],
      "columns": { ... }
    },
    {
      "type": "text-block",
      "text": "Pohledávky v měně {pohledavky.mena}. Bankovní spojení: {pohledavky.banka}."
    }
  ]
}

Placeholdery {pohledavky.mena} a {pohledavky.banka} se resolvují z prvního <row> prvku tabulky pohledavky po aplikaci filterBy — tedy z první věty patřící aktuálnímu odběrateli.

Typické použití:

Poznámka: Pokud filterBy nevrátí žádný řádek pro daný repeat prvek, placeholder vrátí prázdný řetězec. Pole jsou dostupná z prvního filtrovaného řádku — pokud se v tabulce hodnota pole mění řádek od řádku, používejte jen ta pole, která jsou pro celou skupinu konstantní.

Kompletní příklad — hromadné upomínky

JSON šablona:

{
  "document": {
    "repeatElement": "upominky",
    "pageBreakBetween": true,
    "overflow": "flow"
  },
  "blocks": [
    {
      "type": "header-two-column",
      "left": {
        "title": "DODAVATEL",
        "element": "dodavatel",
        "fields": [
          { "field": "nazev", "style": "title" },
          { "field": "ulice" },
          { "template": "{psc}  {mesto}" }
        ]
      },
      "right": {
        "title": "ODBĚRATEL",
        "element": "upominky",
        "bordered": true,
        "fields": [
          { "field": "firma", "style": "title" },
          { "field": "ulice" },
          { "template": "{psc}  {mesto}" }
        ]
      }
    },
    {
      "type": "text-block",
      "element": "upominky",
      "field": "vec",
      "style": "title"
    },
    {
      "type": "table",
      "element": "pohledavky",
      "filterBy": ["organizace"],
      "columns": {
        "faktura": { "label": "Číslo dokladu" },
        "splatna": { "label": "Splatnost", "format": "dd.MM.yyyy" },
        "rozdil": { "label": "K úhradě", "format": "N2", "align": "right" }
      },
      "sumExpressions": [
        { "field": "rozdil", "expr": "SUM(rozdil)", "format": "N2" }
      ],
      "sumLabel": "Celkem"
    },
    {
      "type": "signature",
      "left": "{parametr.sidlo} dne {date}",
      "right": "{upominky.podepsal}"
    }
  ]
}

XML data:

<root>
  <dodavatel nazev="EFES spol. s r.o." ulice="Neklanova 18" psc="128 00" mesto="Praha" />
  <parametr sidlo="Praha" />
  <upominky>
    <row organizace="1001" firma="Alfa s.r.o." ulice="Hlavní 1" psc="110 00"
         mesto="Praha" vec="Upomínka č. 1" podepsal="Jan Novák" />
    <row organizace="1002" firma="Beta a.s." ulice="Vedlejší 5" psc="602 00"
         mesto="Brno" vec="Upomínka č. 2" podepsal="Jan Novák" />
  </upominky>
  <pohledavky>
    <row organizace="1001" faktura="FV001" splatna="2026-01-15" rozdil="15000" />
    <row organizace="1001" faktura="FV002" splatna="2026-02-01" rozdil="8500" />
    <row organizace="1002" faktura="FV003" splatna="2026-01-20" rozdil="42000" />
  </pohledavky>
</root>

Výstup: 2 dokumenty oddělené page-breakem:


20. Průběh renderování (ShowProgress)

Při generování velkých dokumentů (batch tisk faktur) lze zobrazit dialog s průběhem:

loBuilder.ShowProgress = .T.
loBuilder.Render("faktura.pdf", "sablona.json")    && dialog s průběhem
loBuilder.ShowProgress = .F.                        && zpět bez dialogu

Dialog zobrazuje číslo řádku, fázi PDF generování a tlačítko Storno pro přerušení. Property přežívá Reset() i EndBatch().


21. Generování z FoxPro FRX

Existující FoxPro FRX reporty (faktury, dodací listy) lze konvertovat na JSON šablony:

*--- Auto-detekce typu ---
loBuilder.ConvertFrxToAllFiles("C:\frx\VYDANA1A.xml", "C:\output\")

*--- Vynuceně jako dokument (pokud auto-detekce selže) ---
loBuilder.ConvertFrxToDocumentAllFiles("C:\frx\INVUCKC.xml", "C:\output\")
loBuilder.ConvertFrxToDocumentJsonFile("C:\frx\INVUCKC.xml", "C:\output\invuckc.json")

Tip: Auto-detekce rozpozná dokumenty podle výšky PageHeader a Title bandu. Pokud FRX s fakturou klasifikuje jako tabulku, použijte variantu Document v názvu metody.

Inventarizační protokoly (INVUCKC, INVUCSUM2): Automatická konverze FRX inventarizačních protokolů je podporována. Detekce rozpozná typický vzor — PageBreak, groupExpression, nízký Detail band (< 10mm) a GroupFooter s mnoha poli (≥ 10). FRX se konvertuje metodou BuildInventoryDocument(), která generuje: logo, header-two-column, tabulku s filterBy, rekapitulaci, podmíněné texty a podpisy. Více viz sekce 22.


22. Inventarizační protokoly

FRX konvertor automaticky rozpozná inventarizační protokoly (INVUCKC, INVUCSUM2 apod.) a konvertuje je jako dokumenty s repeatElement.

Detekční kritéria

FRX je klasifikován jako inventarizační protokol pokud splňuje:

Generovaná struktura JSON

1. image (logo)
2. header-two-column (adresa + nadpis + podnadpis)
3. separator (thick + thin)
4. table (s filterBy z groupExpression)
5. total-amount (celková částka)
6. rekapitulace (columns s info-gridy: Účetní stav, Zjištěný stav, Rozdíl)
7. podmíněné texty (visibleWhen: shoda/neshoda)
8. signature (datum + vyhotovil/schválil)

FoxPro konverze

*--- Automatická konverze ---
loBuilder.ConvertFrxToAllFiles("C:\frx\INVUCKC.xml", "C:\output\")

*--- Vynuceně jako dokument ---
loBuilder.ConvertFrxToDocumentAllFiles("C:\frx\INVUCKC.xml", "C:\output\")

Klíčové vlastnosti výstupu


23. Skupiny v document tabulce (groups + detailBorders)

Vlastnost groups umožňuje seskupit řádky plochých XML dat v tabulce dokumentu podle hodnoty atributu — podobně jako skupiny v tabulkové sestavě. Každá skupina dostane záhlaví a volitelný sum řádek. Typické použití: rozvaha rozepsaná po účtech, přehled pohybů po střediscích.

Kdy skupiny použít

Alternativa: Pro velké sestavy s mnoha skupinami zvažte tabulkovou sestavu ("renderer": "table") se skupinami — ta má více možností (tableBreak, reprintHeader, XLSX, víceúrovňové skupiny).

Příklad: Rozvaha po účtech

{
  "type": "table",
  "element": "data",
  "detailBorders": "h-dashed",
  "groups": [{
    "groupExpression": "ucet",
    "label": "Účet {ucet} — {ucty.nazev}",
    "headerBackground": "#e8f4fc",
    "detailBorders": "h-dashed",
    "sumExpressions": [
      { "field": "castka", "expr": "SUM(castka)", "format": "N2" }
    ],
    "sumLabel": "Celkem {ucet}",
    "sumBackground": "#f0f0f0"
  }],
  "columns": {
    "text":   { "label": "Popis" },
    "castka": { "label": "Částka", "align": "right", "format": "N2" }
  },
  "sumExpressions": [
    { "field": "castka", "expr": "SUM(castka)", "format": "N2" }
  ],
  "sumLabel": "Celkem za všechny účty"
}

FoxPro příprava dat:

*--- Data musí být setříděna podle groupExpression ---
SELECT ucet, text, castka FROM ucetni_data ORDER BY ucet INTO CURSOR tmpData
CURSORTOXML("tmpData", "lcXml", 3, 16)
loBuilder.AddElementWithXmlContent("data", lcXml)

Vlastnosti skupiny

Vlastnost Typ Výchozí Popis
groupExpression string nebo array Atribut pro detekci změny skupiny. Pro compound klíč: ["ucet", "stredisko"]
label string Šablona záhlaví skupiny. {ucet} = z prvního řádku skupiny
headerBackground string "#e8f4fc" Barva pozadí záhlaví skupiny
detailBorders string Styl čar uvnitř skupiny (viz níže)
sumExpressions array Výrazy pro sum řádek skupiny
sumLabel string Popisek sum řádku skupiny
sumBackground string "#f0f0f0" Barva pozadí sum řádku skupiny

detailBorders — styl čar

Vlastnost detailBorders řídí čáry mezi datovými řádky. Nastavuje se na bloku ("type": "table") nebo na skupině (přepíše blokové nastavení):

Hodnota Popis
"all" Všechny čáry — výchozí
"horizontal" Jen vodorovné čáry (bez svislých)
"vertical" Jen svislé oddělovače (bez vodorovných)
"none" Žádné vnitřní čáry
"inner-none" Žádné čáry ani vnější rám
"h-dashed" Přerušované vodorovné čáry
"h-dashed-only" Přerušované vodorovné, žádné svislé

Příklad — různé styly pro různé skupiny:

{
  "type": "table",
  "element": "polozky",
  "detailBorders": "all",
  "groups": [
    {
      "groupExpression": "kategorie",
      "label": "Kategorie: {kategorie}",
      "detailBorders": "h-dashed"
    }
  ],
  "columns": { ... }
}

Důležité

Data musí být předem setříděná podle groupExpression. Renderer pouze detekuje změny — netřídí data sám. V FoxPro použijte ORDER BY ucet (nebo více polí pro compound klíč).

Grand total se vykreslí z block.sumExpressions po všech skupinách. Pokud nechcete grand total, nevyplňte block.sumExpressions.

Skupiny v dokumentu vs. tabulkové sestavě: Skupiny v document rendereru jsou jednoduchá plochá grupování (jedna úroveň). Pro víceúrovňové skupiny, XLSX export, page break po skupině nebo headerMode external/inline použijte tabulkovou sestavu ("renderer": "table").

Víceřádková patička skupiny (sumRows)

Pro zobrazení více sum řádků za skupinou (celkem, splatné, po splatnosti) použijte sumRows místo jednoduchého sumExpressions + sumLabel:

{
  "groups": [{
    "groupExpression": "mena",
    "label": "Měna: {mena}",
    "sumRows": [
      {
        "sumLabel": "Celkem {mena}",
        "sumExpressions": [{ "field": "castka", "expr": "SUM(castka)", "format": "N2" }],
        "sumBorder": "solid"
      },
      {
        "sumLabel": "Splatné",
        "where": "stav=S",
        "sumBorder": "none",
        "style": "light"
      },
      {
        "sumLabel": "Po splatnosti",
        "where": "stav=P",
        "sumBorder": "none",
        "hideIfZero": true
      }
    ]
  }]
}

Příklad: Kompletní faktura

{
  "version": "1.0",
  "document": {
    "title": "FAKTURA – daňový doklad",
    "culture": "cs-CZ",
    "overflow": "auto",
    "pageMarginMm": 8
  },
  "pageHeader": {
    "left": "EFES spol. s r.o.",
    "right": "Strana {page} z {pages}",
    "fromPage": 2
  },
  "blocks": [
    {
      "type": "columns",
      "ratio": "30:70",
      "verticalAlign": "center",
      "columns": [
        { "blocks": [{ "type": "image", "file": "logo.jpg", "maxWidthMm": 35 }] },
        { "blocks": [{ "type": "text-block", "lines": ["F A K T U R A - daňový doklad"], "style": "title" }] }
      ]
    },
    { "type": "separator", "style": "thick" },
    {
      "type": "header-two-column",
      "left": {
        "title": "DODAVATEL",
        "element": "dodavatel",
        "fields": [
          { "field": "nazev", "style": "title" },
          { "field": "ulice" },
          { "template": "{psc}  {mesto}" },
          { "separator": true },
          { "label": "IČO", "field": "ico" },
          { "label": "DIČ", "field": "dic" }
        ]
      },
      "right": {
        "title": "ODBĚRATEL",
        "element": "odberatel",
        "bordered": true,
        "fields": [
          { "field": "nazev", "style": "title" },
          { "field": "ulice" },
          { "template": "{psc}  {mesto}" },
          { "separator": true },
          { "label": "IČO", "field": "ico" },
          { "label": "DIČ", "field": "dic" }
        ]
      }
    },
    {
      "type": "info-grid",
      "element": "doklad",
      "columns": 2,
      "borderless": true,
      "items": [
        { "label": "Číslo faktury",     "field": "cislo",     "style": "title" },
        { "label": "Variabilní symbol", "field": "vs" },
        { "separator": true },
        { "label": "Způsob úhrady",     "template": "Příkazem k úhradě" },
        { "label": "Den splatnosti",    "field": "splatnost", "format": "dd.MM.yyyy", "style": "bold" }
      ]
    },
    {
      "type": "table",
      "element": "polozky",
      "primary": true,
      "showRowNumbers": true,
      "columns": {
        "nazev": { "label": "Název" },
        "pocet": { "label": "Množství", "align": "right", "format": "N2", "width": "60px" },
        "mj":    { "label": "MJ",       "align": "center", "width": "30px" },
        "jc":    { "label": "Cena/ks",  "align": "right", "format": "N2", "width": "80px" },
        "cena":  { "label": "Celkem",   "align": "right", "format": "N2", "width": "90px" }
      },
      "sumExpressions": [
        { "field": "cena", "expr": "SUM(cena)", "format": "N2" }
      ],
      "sumLabel": "Celkem"
    },
    {
      "type": "total-amount",
      "element": "doklad",
      "field": "celkem_s_dph",
      "label": "Celkem k úhradě",
      "format": "N2",
      "suffix": "Kč",
      "style": "large"
    },
    {
      "type": "text-block",
      "element": "dodavatel",
      "lines": ["{rejstrik}"],
      "style": "small"
    },
    { "type": "separator" },
    {
      "type": "signature",
      "left": "Vystavil: {doklad.vystavil}",
      "right": "Razítko a podpis dodavatele:\nPřevzal: _______________"
    }
  ]
}

Řešení problémů

Nic se nezobrazuje / prázdný dokument

Tabulka nemá řádky

Chybí pole v adrese / info-gridu

Faktura přetéká přes stránku

JSON nejde uložit / červené podtržení

Bloky se zobrazují ve špatném pořadí


Časté úpravy — rychlý přehled

Co chci Kde to nastavit Příklad
Přidat/ubrat pole v adrese header-two-column → fields přidat/smazat objekt
Změnit popisek v info-grid info-grid → items → label "label": "Nový text"
Přidat sloupec do tabulky table → columns přidat klíč + objekt
Skrýt sloupec table → columns → pole "hide": true
Formát čísla format na sloupci/položce "N2", "dd.MM.yyyy"
Přeuspořádat bloky Přesunout blok v poli blocks vyříznout + vložit
Přidat mezeru Vložit spacer blok { "type": "spacer", "heightMm": 10 }
Přidat čáru Vložit separator blok { "type": "separator" }
Podmíněně skrýt blok visibleWhen na bloku "visibleWhen": "header.pole"
Změnit okraje stránky document → pageMarginMm "pageMarginMm": 10
Na šířku document → orientation "orientation": "landscape"
QR platba Přidat qr-code blok viz příklad QR kódu výše
Rámeček kolem odběratele bordered na pravém sloupci "bordered": true
Zobrazit i prázdná pole fieldStyle: "form" na info-grid Prázdná pole se zobrazí jako orámované boxy

Příklad: Jak přidat nový blok

Vložte nový objekt do pole blocks na požadované místo:

"blocks": [
  { "type": "header-two-column", ... },
  { "type": "separator" },
  { "type": "info-grid", ... },
  { "type": "spacer", "heightMm": 5 },
  { "type": "table", ... }
]

Příklad: Jak podmíněně skrýt blok

{
  "type": "info-grid",
  "visibleWhen": "header.je_cizi_mena",
  "element": "doklad",
  "items": [
    { "label": "Měna", "template": "{header.mena}" },
    { "label": "Kurz", "field": "kurz", "format": "N3" }
  ]
}

Celý blok se zobrazí jen pokud header.je_cizi_mena má neprázdnou hodnotu.


Tipy pro VS Code

  1. Ctrl+Space kdekoli → nabídne dostupné vlastnosti podle schématu
  2. Ctrl+Shift+B → ruční renderování (pokud automatické nefunguje)
  3. Červeně podtržené = chyba v JSON → opravte a uložte
  4. Ctrl+Z → zpět (pokud se něco pokazilo)
  5. Formátování JSON: Shift+Alt+F (zarovná odsazení)

Pozor: Za poslední položkou v {} nebo [] nesmí být čárka. Toto je nejčastější chyba při editaci JSON.